                                        /* 老师的代码 */

// #include <iostream>
// #include <vector>
// #include <cstdlib>
// #include <ctime>
// #include <cassert>
// #include <unistd.h>
// #include <sys/wait.h>
// #include <sys/types.h>
// #include "ProcPool.hpp"

// #define PROCESS_NUM 5

// using namespace std;

// int waitCommand(int waitFd, bool &quit) //如果对方不发，我们就阻塞
// {
//     uint32_t command = 0;
//     ssize_t s = read(waitFd, &command, sizeof(command));
//     if (s == 0)
//     {
//         quit = true;
//         return -1;
//     }
//     assert(s == sizeof(uint32_t));
//     return command;


// void sendAndWakeup(pid_t who, int fd, uint32_t command)
// {
//     write(fd, &command, sizeof(command));
//     cout << "main process: call process " << who << " execute " << desc[command] << " through " << fd << endl;
// }

// int main()
// {
//     // 代码中关于fd的处理，有一个小问题，不影响我们使用，但是你能找到吗？？
//     load();
//     // pid: pipefd
//     vector<pair<pid_t, int>> slots;
//     // 先创建多个进程
//     for (int i = 0; i < PROCESS_NUM; i++)
//     {
//         // 创建管道
//         int pipefd[2] = {0};
//         int n = pipe(pipefd);
//         assert(n == 0);
//         (void)n;

//         pid_t id = fork();
//         assert(id != -1);
//         // 子进程我们让他进行读取
//         if (id == 0)
//         {
//             // 关闭写端
//             close(pipefd[1]);
//             // child
//             while (true)
//             {
//                 // pipefd[0]
//                 // 等命令
//                 bool quit = false;
//                 int command = waitCommand(pipefd[0], quit); //如果对方不发，我们就阻塞
//                 if (quit)
//                     break;
//                 // 执行对应的命令
//                 if (command >= 0 && command < handlerSize())
//                 {
//                     callbacks[command]();
//                 }
//                 else
//                 {
//                     cout << "非法command: " << command << endl;
//                 }
//             }
//             exit(1);
//         }
//         // father,进行写入，关闭读端
//         close(pipefd[0]); // pipefd[1]
//         slots.push_back(pair<pid_t, int>(id, pipefd[1]));
//         // cout << "pipefd[1] = " << pipefd[1] << endl;
//     }
//     // 父进程派发任务
//     srand((unsigned long)time(nullptr) ^ getpid() ^ 23323123123L); // 让数据源更随机
//     while (true)
//     {
//         // 选择一个任务, 如果任务是从网络里面来的？
//         int command = rand() %  handlerSize();
//         // 选择一个进程 ，采用随机数的方式，选择进程来完成任务，随机数方式的负载均衡
//         int choice = rand() % slots.size();
//         // 把任务给指定的进程
//         sendAndWakeup(slots[choice].first, slots[choice].second, command);
//         sleep(1);
//     }

//     // 关闭fd, 所有的子进程都会退出
//     for (const auto &slot : slots)
//     {
//         close(slot.second);
//     }

//     // 回收所有的子进程信息
//     for (const auto &slot : slots)
//     {
//         waitpid(slot.first, nullptr, 0);
//     }
//     return 0;
// }













                                                /* 自己写 */
// 管道的实现
// 1.两个fd(读和写)指向同一文件(pipefd)
// 2.创建子进程
// 3.关闭各自不需要的pipefd，以确保信道的单向性

#include <iostream>
#include <unistd.h>
#include <assert.h>
#include <vector>

#include <ctime>
#include <cstdlib>

#include <sys/types.h>
#include <sys/wait.h>

#include "ProcPool.hpp"

using namespace std;

#define ProcNum 5
// 创建子进程的数量

int main()
{
    vector< pair<pid_t, int> > mp;
    // {id, pipefd}

    load();
    for (int i = 0; i < ProcNum; i++)
    {
        // 1.两个fd(读和写)指向同一文件(pipefd)
        int pipefd[2] = {0};

        int n = pipe(pipefd);
        // pipe:
        // 1.返回值：成功为0， 失败为-1
        // 2.pipefd：输出型参数

        assert(n != -1);
        // 括号中不满足就退出
        (void)n;
        // 在release版本下，assert会被删掉，若没有这一行代码，就会造成变量未使用的报警

        // 2.创建子进程
        pid_t id = fork();
        if (id == 0)
        {
            // 子进程
            // 关掉写
            close(pipefd[1]);

            // 读
            while (true)
            {
                // int commod = 0;
                uint32_t commod = 0;
                ssize_t s = read(pipefd[0], &commod, sizeof(commod));
                if (s == 0)
                    break;
                assert(s == sizeof(commod));

                if (commod >= 0 && commod < vec.size())
                    vec[commod]();
                else
                    cout << "非法commod" << endl;
            }

            close(pipefd[0]);
            // 可写可不写，因为退出后会自动关闭所有文件描述符

            // 退出，不执行后面的父进程代码
            exit(0);
        }
        
        // 父进程
        close(pipefd[0]);
        // mp.insert(pair<pid_t, int>{id, pipefd[1]});
        mp.push_back(pair<pid_t, int>(id, pipefd[1]));
    }

    // 随机分配任务给子进程, 确保负载均衡
    srand((unsigned int)time(NULL));
    // srand: stdlib文件中

    while (true)
    {
        uint32_t commod = rand() % getFuncSize();// 选择一个任务
        int choice = rand() % mp.size();// 选择一个进程去完成

        write(mp[choice].second, &commod, sizeof(commod));
        sleep(1);
    }

    // 最后的处理
    for (auto it : mp)
    {
        // 关闭所有文件描述符
        close(it.second);
    }

    for (auto it : mp)
    {
        // 处理所有子进程推出信息
        waitpid(it.first, NULL, 0);
    }

    return 0;
}
